<template>
	<div class="base-input mb-4">
		<div class="w-full relative flex flex-col justify-end">
			<div
				v-if="label || labelT || expandable || required || !!$slots.title"
				class="base-input-title"
				:class="expanded ? 'h-[26px]' : 'h-5'">
				<slot name="title">
					<div class="flex items-center">
						<div @click.stop="clickExpandedWithLabel && handleExpanded()">
							<base-text
								:text="label"
								:textT="labelT"
								:class="clickExpandedWithLabel ? 'cursor-pointer' : 'pointer-events-none'" />
							<span v-if="required" class="text-danger">&nbsp;*</span>
						</div>
						<base-icon
							v-if="expandable"
							name="down2"
							size="16"
							class="ml-2 duration-300 relative top-[1px] cursor-pointer"
							:class="{ 'rotate-180': expanded }"
							@click.stop="handleExpanded()" />
					</div>
				</slot>
			</div>
			<template v-if="expanded">
				<n-popover
					:show="showPopover"
					:animated="false"
					:placement="isPC() ? 'left' : 'bottom'"
					v-bind="NBind.Popover">
					<template #trigger>
						<div class="h-12 flex" :class="inputWrapperClass">
							<slot name="prefix-out" />
							<div
								class="w-full h-full flex items-center rounded-lg px-3 gap-3 bg-bg-2 border border-bg-2 hover:border-primary transition-colors duration-300"
								:class="[
									{
										'!border-danger': isDanger,
										'!border-warning': isWarning,
										'!border-success': isSuccess,
										'!border-bg-2': readonly,
										'border-primary': _focus
									},
									contentClass
								]"
								@click="inputRef?.focus()">
								<slot name="prefix" />
								<input
									ref="inputRef"
									:value="modelValue"
									:type="computedType"
									:name="name"
									class="flex-1 p-0 peer w-full h-full bg-transparent text-t-1 focus:border-primary outline-none transition-all border-none app-font-bold"
									:class="[{ 'text-t-3': readonly }, inputClass]"
									:placeholder="placeholderText"
									:readonly="readonly"
									@compositionstart="compositionstart"
									@compositionend="compositionend"
									@focus="onFocus"
									@blur="onBlur"
									@input="onChange"
									v-bind="inputProps" />
								<base-icon
									v-show="clearable && !readonly && modelValue"
									class="text-t-3 app-text-react"
									name="remove"
									size="16"
									@click="onClear" />
								<base-icon
									v-if="passwordIcon"
									class="text-t-3 app-text-react"
									:name="passwordIcon"
									size="16"
									@click="passVisible = !passVisible" />
								<slot name="suffix" />
							</div>
							<slot name="suffix-out" />
						</div>
					</template>
					<base-input-error :text="error" :textT="errorT" />
					<base-input-rule :options="rules" />
				</n-popover>
			</template>
			<div
				v-if="false"
				class="absolute w-full bottom-0"
				:class="[
					_focus ? 'h-[2px] bg-primary' : 'h-[1px] bg-border-3',
					{ '!bg-danger': isDanger }
				]" />
		</div>
		<!--		<div class="min-h-[18px] flex items-center">-->
		<!--			<base-input-error :text="error" :textT="errorT" />-->
		<!--			<base-input-rule :options="rules" />-->
		<!--		</div>-->
	</div>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { NPopover } from 'naive-ui'
import { some } from 'lodash-es'
import BaseIcon from '@/components/base/icon/index.vue'
import BaseInputError from '@/components/base/input-error/index.vue'
import BaseText from '@/components/base/text/index.vue'
import BaseInputRule, { RuleType } from '@/components/base/input-rule/index.vue'
import { isPC, t, tInput } from '@/utils'
import { NBind } from '@/plugins/naive-ui'

const props = defineProps({
	modelValue: {
		type: [String, Number],
		required: true
	},
	focus: {
		type: Boolean,
		default: false
	},
	name: {
		type: String,
		default: ''
	},
	label: {
		type: String,
		default: ''
	},
	labelT: {
		type: [String, Array],
		default: ''
	},
	error: {
		type: String,
		default: ''
	},
	errorT: {
		type: [String, Array],
		default: ''
	},
	type: {
		type: String,
		default: 'text'
	},
	autofocus: {
		type: Boolean,
		default: false
	},
	clearable: {
		type: Boolean,
		default: true
	},
	required: {
		type: Boolean,
		default: false
	},
	readonly: {
		type: Boolean,
		default: false
	},
	expandable: {
		type: Boolean,
		default: false
	},
	expanded: {
		type: Boolean,
		default: true
	},
	clickExpandedWithLabel: {
		type: Boolean,
		default: false
	},
	placeholder: {
		type: String,
		default: ''
	},
	placeholderT: {
		type: [String, Array],
		default: ''
	},
	contentClass: {
		type: [String, Array, Object],
		default: ''
	},
	inputClass: {
		type: [String, Array, Object],
		default: ''
	},
	inputWrapperClass: {
		type: [String, Array, Object],
		default: ''
	},
	// 输入时过滤不允许输入的字符,(账号密码不允许输入表情和中文等..);
	filter: {
		type: [Object, Function],
		default: null
	},
	// 如果外部传入modelValue有不允许的字符,进行强制过滤;
	filterForce: {
		type: Boolean,
		default: false
	},
	rules: {
		type: Array<RuleType>,
		default: () => []
	},
	inputProps: {
		type: Object
	},
	isDanger: {
		type: Boolean,
		default: false
	},
	isWarning: {
		type: Boolean,
		default: false
	},
	isSuccess: {
		type: Boolean,
		default: false
	}
})

const emits = defineEmits([
	'update:modelValue',
	'update:focus',
	'update:expanded',
	'focus',
	'blur',
	'clear'
])

const inputRef = ref<HTMLInputElement | null>(null)

// 拼写模式输入状态ios(包括但不仅限于中文);
const compositionStatus = ref(false)

const compositionstart = () => {
	compositionStatus.value = true
}
const compositionend = () => {
	compositionStatus.value = false
	nextTick(() => onChange({ target: { value: props.modelValue } }))
}

const onChange = (event: any) => {
	let value = event.target.value
	if (props.type === 'code') {
		let value = event.target.value
		value = value.replace(/\D/g, '')
		event.target.value = value
	}
	// 拼写模式下不要处理空字符,否则会拼写会被中断,ios上会出现字符累加现象
	if (!compositionStatus.value) {
		if (props.filter instanceof RegExp) {
			value = String(value).replace(props.filter, '')
		} else if (typeof props.filter === 'function') {
			value = props.filter(value)
		}
	}
	if (inputRef.value && inputRef.value.value !== value) {
		inputRef.value.value = value
	}

	emits('update:modelValue', value)
}

const _focus = ref(false)

const onFocus = () => {
	_focus.value = true
	emits('update:focus', true)
	emits('focus')
}

const onBlur = () => {
	_focus.value = false
	emits('update:focus', false)
	emits('blur')
}

const onClear = () => {
	emits('update:modelValue', '')
	emits('clear', '')
	inputRef.value?.focus?.()
}

const showPopover = computed(() => {
	return (
		!!props.error || !!props.errorT || (!!props.rules.length && some(props.rules, { valid: false }))
	)
})

const passVisible = ref(false)

const computedType = computed(() => {
	if (props.type === 'password') {
		return passVisible.value ? 'text' : 'password'
	}
	return props.type
})

const passwordIcon = computed(() => {
	if (props.type === 'password') {
		return passVisible.value ? 'open-eyes' : 'close-eyes'
	}
	return ''
})

// 默认占位符与labelT,可以内部自动拼接 支持labelT;纯文本需要单独传入placeholder和label
const placeholderText = computed(() =>
	props.placeholder
		? props.placeholder
		: props.placeholderT
			? Array.isArray(props.placeholderT)
				? t(...(props.placeholderT as [string, any[] | object]))
				: t(props.placeholderT)
			: props.label
				? t('tip.input') + String(props.label).toLowerCase()
				: tInput(props.labelT)
)

const handleExpanded = () => {
	emits('update:expanded', !props.expanded)
	if (!props.expanded) {
		nextTick(() => inputRef.value?.focus())
	}
}

watch(
	() => props.modelValue,
	(value) => {
		// 如果外部传入modelValue有不允许的字符,在这里处理;
		if (props.filter && props.filterForce) {
			nextTick(() => onChange({ target: { value } }))
		}
	},
	{ immediate: true }
)

onMounted(() => {
	props.autofocus && inputRef.value?.focus()
})

defineExpose({ getTarget: () => inputRef.value })
</script>

<style scoped lang="scss">
.base-input {
	input {
		&:-webkit-autofill,
		&:-webkit-autofill:focus {
			-webkit-text-fill-color: var(--color-text-1);
			-webkit-box-shadow: 0 0 0 1000px var(--color-bg-2) inset !important;
		}
		&::placeholder {
			color: var(--color-text-3);
		}
		//&:placeholder-shown {
		//	background: var(--color-bg-2);
		//}
	}
	// 隐藏 PC 端 <input type="number"> 右侧显示的上下箭头
	/* Chrome, Safari, Edge, Opera */
	input[type='number']::-webkit-outer-spin-button,
	input[type='number']::-webkit-inner-spin-button {
		-webkit-appearance: none;
		margin: 0;
	}
	/* Firefox */
	input[type='number'] {
		-moz-appearance: textfield;
	}
}
</style>
